perm filename PMOV[S1,ALS] blob sn#402194 filedate 1978-12-13 generic text, type C, neo UTF8
COMMENT āŠ—   VALID 00002 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00002 00002	PMOV :
C00009 ENDMK
CāŠ—;
PMOV :
    begin (*PMOV*)

    (* LCW 2AUG78 Modified by ALS 3Dec78
    The strategy for PMOV is to do a BLKMOV if the transfer length is long
    enough to justify the BLKMOV overhead,
    else if (I1 mod 4)=0 then if (([OPND1] mod 4)=0 and ([OPND2] mod 4)=0)
    then do a series of MOVMSs starting with the longest available MOVMS and
    proceeding to the short MOVMSs if necessary,
    else to do a series of MOVMQs, starting with the longest available MOVMQ
    and proceeding to the short MOVMQs if necessary.

    This procedure ignores the problem associated with having overlapping
    source and destination where the source address is less than the
    destination address.  In that case, SOPA may destroy the source during
    the MOV.  However, if the source and destination overlap completely,
    then SOPA will not destroy the source.  Note that PASCAL and PCode do
    not explicitly define the semantics of MOV when the source and
    destination incompletely overlap.
    *)

    if not (STK[TOP-1].DTYPE in [TYPA,TYPM]) or
       not (STK[TOP].DTYPE in [TYPA,TYPM]) then
	ERROR (WMOV_NEEDS_ADDRS);

    if I1 >= BLKMOV_THRESH then
	begin (*generate BLKMOV*)

	(*make sure that the global zero and CPL are free (error if not)*)
	ALLOCGBL (S1GBLZ);
	ALLOCRG (S1RCPL);
	ALLOCRG (succ(S1RCPL));
	ALLOCRG (succ(succ(S1RCPL)));

	(* initialize the global zero *)
	OP1GBL := S1GBLZ;
	ADDR_OPERAND (OPND1, OP1GBL*WORDUNITS);
	EMITXOP (XMOV_S_S, OPND1, ZERO_OP);

	(*initialize the CPL block descriptor*)
	REG_OPERAND (OPNDR1, S1RCPL);
	IMM_OPERAND (OPND2, S1GBLZ*WORDUNITS);
	EMITXOP (XMOV_S_S, OPNDR1, OPND2);

	REG_OPERAND (OPNDR1, succ(S1RCPL));
	MOVE_QUANTITY (OPNDR1, TOP-1);

	REG_OPERAND (OPNDR1, succ(succ(S1RCPL)));
	IMM_OPERAND (OPND2, I1);
	EMITXOP (XMOV_S_S, OPNDR1, OPND2);

	(*emit the BLKMOV*)
	REG_OPERAND (OPNDR1, S1RCPL);
	GET_ADDRESS (OPND2, TOP);
	EMITXOP (XBLKMOV, OPNDR1, OPND2);

	(*free the global zero and CPL registers*)
        FREEGBL_S (S1GBLZ);
	FREERG_S (S1RCPL);
	FREERG_S (succ(S1RCPL));
	FREERG_S (succ(succ(S1RCPL)));

	end (*generate BLKMOV*)
    else
 	begin (*generate MOVMSs or MOVMQs after test*)
	if ((I1 mod 4)=0 and
	ZZZZZZZZ Code to see if starts are on word boundaries ZZZZZZZZ  )
	then
	    begin (*generate MOVMS*)
	    XFER_CNT := I1/4;

	    while XFER_CNT >= 32 do
		begin
		GET_ADDRESS (OPND1, TOP-1);
		GET_ADDRESS (OPND2, TOP);
		EMITXOP (XMOVMS_32, OPND1, OPND2);
		XFER_CNT := XFER_CNT - 32;
		if XFER_CNT > 0 then
		    begin
		    INCREMENT_DATUM (TOP-1, 128);
		    INCREMENT_DATUM (TOP, 128);
		    end;
		end;
	       
	    if XFER_CNT > 0 then
		begin
		GET_ADDRESS (OPND1, TOP-1);
		GET_ADDRESS (OPND2, TOP);
		EMITXOP (MOVMS_N[XFER_CNT], OPND1, OPND2);
		end;

	    end (*generate MOVMS*)
	else
	    begin (*generate MOVMQ*)
	    XFER_CNT := I1;

	    while XFER_CNT >= 128 do
		begin
		GET_ADDRESS (OPND1, TOP-1);
		GET_ADDRESS (OPND2, TOP);
		EMITXOP (XMOVMQ_128, OPND1, OPND2);
		XFER_CNT := XFER_CNT - 128;
		if XFER_CNT > 0 then
		    begin
		    INCREMENT_DATUM (TOP-1, 128);
		    INCREMENT_DATUM (TOP, 128);
		    end;
		end;
	       
	    if XFER_CNT >= 64 then
		begin
		GET_ADDRESS (OPND1, TOP-1);
		GET_ADDRESS (OPND2, TOP);
		EMITXOP (XMOVMQ_64, OPND1, OPND2);
		XFER_CNT := XFER_CNT - 64;
		if XFER_CNT > 0 then
		    begin
		    INCREMENT_DATUM (TOP-1, 64);
		    INCREMENT_DATUM (TOP, 64);
		    end;
		end;
	       
	    if XFER_CNT >= 32 then
		begin
		GET_ADDRESS (OPND1, TOP-1);
		GET_ADDRESS (OPND2, TOP);
		EMITXOP (XMOVMQ_32, OPND1, OPND2);
		XFER_CNT := XFER_CNT - 32;
		if XFER_CNT > 0 then
		    begin
		    INCREMENT_DATUM (TOP-1, 32);
		    INCREMENT_DATUM (TOP, 32);
		    end;
		end;
	       
	    if XFER_CNT > 0 then
		begin
		GET_ADDRESS (OPND1, TOP-1);
		GET_ADDRESS (OPND2, TOP);
		EMITXOP (MOVMQ_N[XFER_CNT], OPND1, OPND2);
		end;

	end (*generate MOVMQ*)
    end (*generate MOVMS or MOVMQ);
    FREEDATUMREGS (TOP);
    POPTOP;
    FREEDATUMREGS (TOP);
    POPTOP;
    end (*PMOV*);